#ifndef SPH_DRAW_HELPERS_HEADER
#define SPH_DRAW_HELPERS_HEADER

#include "Particle.h"
#include "GL/glfw.h"
#include "glm/glm.hpp"

struct Bounds {
	glm::vec3 min;
	glm::vec3 max;
};

struct Cube {
	Bounds bounds[3]; //axis x, axis y, axis z
};

void DrawVector( const glm::vec3 & start, const glm::vec3 & vec, float leng = 1.0f ){
	glBegin(GL_LINES);
	glVertex3fv(&start[0]);
	glVertex3f(start.x + vec.x*leng, start.y + vec.y*leng, start.z + vec.z*leng);
	glEnd();
}

void DrawSolidCircle( const glm::vec3 & origin, float rad, const std::vector<glm::vec2> & circleVerts ) {
	glBegin(GL_TRIANGLE_FAN);
		glVertex3fv( &origin[0] );

		for (int i = 0; i < circleVerts.size(); ++i) {
			glVertex3f(circleVerts[i].x*rad + origin.x,
				circleVerts[i].y*rad + origin.y,
				origin.z);
		}

	glEnd();
}

void DrawHollowCircle( const glm::vec3 & origin, float rad, const std::vector<glm::vec2> & circleVerts ) {
	unsigned int s = circleVerts.size();
	glBegin(GL_LINES);
		for (int i = 0; i < circleVerts.size(); ++i) {
			glVertex3f(circleVerts[i].x*rad + origin.x,
				circleVerts[i].y*rad + origin.y,
				origin.z);
			glVertex3f(circleVerts[(i+1) %s ].x*rad + origin.x,
				circleVerts[(i+1)%s].y*rad + origin.y,
				origin.z);
		}

	glEnd();
}

void DrawSupport( const glm::vec3 & inPart ) {
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);	
}

void DrawForces(const std::vector<glm::vec3> & inForces, const ParticleCollection & pc){
	if (inForces.size() == 0){
		return;
	}

	glBegin(GL_LINES);
	unsigned int cntr = 0;

	for (ConstParticleIter it = pc.cbegin();
		it != pc.end(); ++it){
			DrawVector(it->pos, inForces[cntr++]);	
	}

	glEnd();	
}



void DrawNormals(const std::vector<glm::vec3> & normField, const ParticleCollection & pc) {
	if (normField.size() == 0) {
		return;
	}
	glBegin(GL_LINES);
	
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend(); ++it){
			DrawVector(it->f, normField[it->ndx]);		
	}

	glEnd();
}

void DrawParticles(const ParticleCollection & pc, const std::vector<float> & pressure) {
	float maxPres = std::numeric_limits<float>::min();
	float minPres = std::numeric_limits<float>::max();
	//Get max/min
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend(); 
		++it) {
			if (pressure[it->ndx] > maxPres) { maxPres = pressure[it->ndx]; }
			if (pressure[it->ndx] < minPres) { minPres = pressure[it->ndx]; }
	}
	
	//Draw
	glPointSize(5.0);
	glBegin(GL_POINTS);
	ConstParticleIter en = pc.cend();
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend();
		++it ) {
			unsigned int ndx = it->ndx;
			float r = pressure[ndx] > 0 ? std::fabs(pressure[ndx]/ maxPres) : 0.0;
			float b = pressure[ndx] < 0 ? std::fabs(pressure[ndx] / minPres) : 0.0;
			glColor3f( r,
				0.0,
				 b);
			glVertex3fv(&(it->pos[0]));
	}
	glEnd();
}

void Draw2DBox( const Bounds & inBounds) {
	glLineWidth(3.0);

	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glBegin(GL_QUADS);

	glVertex2f(inBounds.min[0], inBounds.min[1]);
	glVertex2f(inBounds.max[0], inBounds.min[1]);
	glVertex2f(inBounds.max[0], inBounds.max[1]);
	glVertex2f(inBounds.min[0], inBounds.max[1]);

	glEnd();

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

void DrawBox( const Bounds & inBounds ) {
	glLineWidth(3.0);

	glBegin(GL_LINES);
	glVertex3f(inBounds.min[0], inBounds.min[1], inBounds.min[2]);
	glVertex3f(inBounds.max[0], inBounds.min[1], inBounds.min[2]);

	glVertex3f(inBounds.min[0], inBounds.max[1], inBounds.min[2]);
	glVertex3f(inBounds.max[0], inBounds.max[1], inBounds.min[2]);

	glVertex3f(inBounds.min[0], inBounds.max[1], inBounds.max[2]);
	glVertex3f(inBounds.max[0], inBounds.max[1], inBounds.max[2]);

	glVertex3f(inBounds.min[0], inBounds.min[1], inBounds.max[2]);
	glVertex3f(inBounds.max[0], inBounds.min[1], inBounds.max[2]);

	//
	glVertex3f(inBounds.min[0], inBounds.min[1], inBounds.min[2]);
	glVertex3f(inBounds.min[0], inBounds.max[1], inBounds.min[2]);

	glVertex3f(inBounds.max[0], inBounds.min[1], inBounds.min[2]);
	glVertex3f(inBounds.max[0], inBounds.max[1], inBounds.min[2]);

	glVertex3f(inBounds.max[0], inBounds.min[1], inBounds.max[2]);
	glVertex3f(inBounds.max[0], inBounds.max[1], inBounds.max[2]);

	glVertex3f(inBounds.min[0], inBounds.min[1], inBounds.max[2]);
	glVertex3f(inBounds.min[0], inBounds.max[1], inBounds.max[2]);
	glEnd();
}

void DrawSupportRad( const ParticleCollection & pc, float supportRad, const std::vector<glm::vec2> & circleVerts) {
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend(); ++it) {
		DrawHollowCircle(glm::vec3(it->pos.x, it->pos.y, -1), supportRad, circleVerts);
	}	
}

void DrawOutlines(const ParticleCollection & pc, const std::vector<glm::vec2> & circleVerts) {
	float rad = 0.2;
	float lineWid = 0.05f;

	glColor3f(1.0, 0.0, 0.0);
	//glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend(); ++it) {
		DrawSolidCircle(glm::vec3(it->pos.x, it->pos.y, -1), rad, circleVerts);
	}	

	glColor3f(1.0,1.0,1.0);
	for (ConstParticleIter it = pc.cbegin();
		it != pc.cend(); ++it) {
		DrawSolidCircle(glm::vec3(it->pos.x, it->pos.y, 0), rad - lineWid, circleVerts);
	}
}

#endif